package com.sdy.mvc.feign;

import feign.CollectionFormat;
import feign.Contract;
import feign.MethodMetadata;
import feign.Request;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.stream.Collectors;

import static feign.Util.checkState;

/**
 * 自定义RPC合约
 * @author zhouziqiang
 */
@Slf4j
public class RpcContract extends Contract.BaseContract {
    @Override
    protected void processAnnotationOnClass(MethodMetadata data, Class<?> clz) {
    }

    @Override
    protected void processAnnotationOnMethod(MethodMetadata data, Annotation methodAnnotation, Method method) {
        Class<? extends Annotation> annotationType = methodAnnotation.annotationType();
        if (annotationType == PostMapping.class) {
            String[] urls = ((PostMapping) methodAnnotation).value();
            checkState(urls.length > 0,
                    "PostMapping annotation was empty on method %s.", method.getName());
            data.template().method(Request.HttpMethod.POST);
            data.template().uri(urls[0]);
            data.template().decodeSlash(true);
            data.template().collectionFormat(CollectionFormat.EXPLODED);
            if (Arrays.stream(method.getParameters()).anyMatch(parameter -> !parameter.isNamePresent())) {
                log.error("Parameter's real name is not present! Please enable parameter information in ide settings.");
                System.exit(-1);
            }
            data.formParams().addAll(Arrays.stream(method.getParameters())
                    .map(Parameter::getName)
                    .collect(Collectors.toList())
            );
        }
    }

    @Override
    protected boolean processAnnotationsOnParameter(MethodMetadata data, Annotation[] annotations, int paramIndex) {
        String name = data.formParams().get(paramIndex);
        nameParam(data, name, paramIndex);
        data.indexToEncoded().put(paramIndex, false);
        return true;
    }
}
